#-*- coding:utf-8 -*-

import configparser
import os
import sys
import serial
import socket
import traceback
import threading
import time
import queue
import logging
import logging.handlers

from BDLib import *


class UART2TCP:

    mutex = threading.Lock()
    bdrx = []
    bdtx = []
    s = []
    c = []
    a = []

    def __init__(self):
        try:
            if not os.path.exists("Log"):
                os.makedirs("Log")

            self.conf = configparser.ConfigParser()
            self.conf.read(os.path.basename(sys.argv[0]).split('.')[0] + '.ini', 'utf-8')

            self.com = serial.Serial(self.conf.get('config', 'lcdcom'), 115200)

            self._com = self.conf.get('config', 'bdcom').split(',')
            self._baud = self.conf.get('config', 'bdbaud').split(',')
            self._port = self.conf.get('config', 'bdport').split(',')

            self._loglevel = self.conf.getint('log', 'level')
            self._logdays = self.conf.getint('log', 'days')
            self.logger = self._getLogger()
            self.logger.critical('UART2TCP v1.20 start....')
        except:
            traceback.print_exc()
            input('Press any key to close this window')
            os._exit(0)


    def _getLogger(self):
        logger = logging.getLogger('')

        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(message)s'))
        logger.addHandler(handler)
        handler = logging.handlers.TimedRotatingFileHandler(os.path.join('Log', 'uart2udp.log'), when='MIDNIGHT', interval=1, backupCount=self._logdays)
        handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(message)s'))
        logger.addHandler(handler)
        logger.setLevel(self._loglevel)

        return logger


    def thd_Port_Send(self, i):
        while True:
            try:
                d = self.bdrx[i].get()
                if self.a[i][1]:
                    self.s[i].sendto(d, self.a[i])
            except:
                self.logger.error(traceback.format_exc())


    def thd_Port_Recv(self, i):
        while True:
            try:
                d, addr = self.s[i].recvfrom(4096)
                self.a[i] = addr
                self.bdtx[i].put(d)
            except:
                self.logger.error(traceback.format_exc())


    def thd_COM_Recv(self, i):
        while True:
            try:
                d = self.c[i].read_until(b'\r\n')
                self.bdrx[i].put(d)
                self.logger.debug(('[%d] << ' % i) + d.decode(encoding = "gbk", errors = "ignore"))
                if d.startswith(b'$BDPWI'):
                    self.mutex.acquire()
                    tx = ('$BDPWI%d' % i).encode() + d[6:] + b'\r\n'
                    self.com.write(tx)
                    self.mutex.release()
            except:
                self.logger.error(traceback.format_exc())


    def thd_COM_Send(self, i):
        while True:
            try:
                d = self.bdtx[i].get()
                self.c[i].write(d)
                self.logger.debug(('[%d] >> ' % i) + d.decode(encoding = "gbk", errors = "ignore"))
            except:
                self.logger.error(traceback.format_exc())


    def Start(self):
        filename = os.path.basename(sys.argv[0]).split('.')[0] + '.running'

        try:
            for i in range(len(self._com)):
                self.s.append(socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
                self.c.append(serial.Serial(self._com[i], self._baud[i]))
                self.s[i].bind(('0.0.0.0', int(self._port[i])))
                self.a.append(('', 0))
                self.bdrx.append(queue.Queue())
                self.bdtx.append(queue.Queue())
                threading._start_new_thread(self.thd_Port_Recv, (i,))
                threading._start_new_thread(self.thd_Port_Send, (i,))
                threading._start_new_thread(self.thd_COM_Recv, (i,))
                threading._start_new_thread(self.thd_COM_Send, (i,))

        except:
            traceback.print_exc()
            input('Press any key to close this window')
            os._exit(0)

        while True:
            try:
                time.sleep(5)
                tnow = int(time.time())
                os.utime(filename, (tnow, tnow))
            except:
                self.logger.error(traceback.format_exc())


if __name__=='__main__':
    UART2TCP().Start()
